package com.mia.craftstudio;

import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class CSPack {
   private final Map entries = new HashMap();
   private final String name;
   private byte version;
   private static final Logger LOGGER = LogManager.getLogger();
   transient CSProject project = null;
   private final IPackReaderCallback callback;

   public CSPack(String name, IPackReaderCallback callback) {
      this.name = name;
      this.callback = callback;
   }

   public String getName() {
      return this.name;
   }

   public byte getVersion() {
      return this.version;
   }

   public BiMap getEntries() {
      return ImmutableBiMap.copyOf(this.entries);
   }

   void readPackFile(InputStream overrideStream) throws CSExceptions.NoCSProjectException {
      if (this.project == null) {
         throw new CSExceptions.NoCSProjectException();
      } else {
         try {
            this.entries.clear();
            Locale localeOriginal = Locale.getDefault();
            LOGGER.info(String.format("Original locale was %s, switching to Locale.US", localeOriginal));
            Locale.setDefault(Locale.US);
            LOGGER.info(String.format("Locale is now %s", Locale.getDefault()));
            Map descriptors = new HashMap();
            String path = String.format("%s/%s", this.project.getProjectAssetPath(), this.name);
            ZipInputStream zis = new ZipInputStream(CSPack.class.getResourceAsStream(path));
            InputStream jsonStream = overrideStream != null ? overrideStream : CSPack.class.getResourceAsStream(String.format("%s/%s", this.project.getProjectAssetPath(), this.name.replace(".cspack", ".json")));
            if (jsonStream != null) {
               byte[] buffer = new byte[4096];
               ByteArrayOutputStream outstream = new ByteArrayOutputStream();

               while(true) {
                  int len = jsonStream.read(buffer);
                  if (len == -1) {
                     String jsonString = outstream.toString();

                     JsonElement rootElement;
                     try {
                        JsonParser jsonParser = new JsonParser();
                        JsonReader jsonReader = new JsonReader(new StringReader(jsonString));
                        jsonReader.setLenient(true);
                        rootElement = jsonParser.parse(jsonReader);
                     } catch (Throwable var17) {
                        LOGGER.error(outstream.toString());
                        throw new RuntimeException(var17);
                     }

                     if (rootElement.isJsonArray()) {
                        JsonArray jsonList = rootElement.getAsJsonArray();
                        Iterator var26 = jsonList.iterator();

                        while(var26.hasNext()) {
                           JsonElement element = (JsonElement)var26.next();
                           if (element.isJsonObject()) {
                              descriptors.put(element.getAsJsonObject().get("craftstudioAssetID").getAsInt(), element);
                           }
                        }
                     }
                     break;
                  }

                  outstream.write(buffer, 0, len);
               }
            }

            Locale.setDefault(localeOriginal);
            LOGGER.info(String.format("Locale was restored to %s", localeOriginal));
            ReadableByteChannel zipByteChan = Channels.newChannel(zis);
            if (this.callback != null) {
               this.callback.setCount(descriptors.size());
            }

            ZipEntry ze;
            while((ze = zis.getNextEntry()) != null) {
               ByteBuffer bbuf = ByteBuffer.allocate((int)ze.getSize());
               zipByteChan.read(bbuf);
               bbuf.order(ByteOrder.LITTLE_ENDIAN).rewind();
               if (ze.getName().indexOf(47) > 0) {
                  String[] nameParts = ze.getName().split("[/.]");
                  Integer id = Integer.valueOf(nameParts[nameParts.length - 2]);
                  String type = nameParts[nameParts.length - 1];
                  if ("csmodel".equals(type)) {
                     try {
                        CSModel model = new CSModel(bbuf);
                        this.project.addModel(id, model);
                        if (this.callback != null) {
                           this.callback.modelLoaded(model, (JsonElement)descriptors.get(id));
                        }
                     } catch (CSExceptions var16) {
                        CraftStudioLib.getLog().info(String.format("Skipping Asset %s: %s", id, var16.getMessage()));
                     }
                  }

                  if ("csmodelanim".equals(type)) {
                     try {
                        this.project.addAnimation(id, new CSModelAnim(bbuf));
                     } catch (CSExceptions var15) {
                        CraftStudioLib.getLog().info(String.format("Skipping Asset %s: %s", id, var15.getMessage()));
                     }
                  }

                  if (descriptors.containsKey(id)) {
                     this.project.addDescriptor(id, (JsonElement)descriptors.get(id));
                  }
               } else if ("DataPackage.dat".equals(ze.getName())) {
                  try {
                     this.readDataPackage(bbuf);
                  } catch (CSExceptions var14) {
                     CraftStudioLib.getLog().info(String.format("Error while reading CSPack: %s", var14.getMessage()));
                  }
               }
            }
         } catch (IOException var18) {
            var18.printStackTrace();
         }

      }
   }

   private void readDataPackage(ByteBuffer buffer) throws CSExceptions.UnsupportedVersionException {
      this.version = buffer.get();
      short entry_count = buffer.getShort();

      while(entry_count-- > 0) {
         CSPack.ProjectEntry entry = new CSPack.ProjectEntry(buffer);
         CraftStudioLib.debug(entry);
         this.entries.put(Integer.valueOf(entry.getID()), entry);
      }

   }

   CSPack cleanup() {
      this.entries.clear();
      this.project = null;
      return this;
   }

   public static class ProjectEntry {
      private final boolean folder;
      private final short id;
      private final short parent_id;
      private final String name;
      private final byte type;
      private final boolean locked;

      public ProjectEntry(ByteBuffer buffer) {
         this.folder = buffer.get() != 0;
         this.id = buffer.getShort();
         this.parent_id = buffer.getShort();
         byte[] tmpName = new byte[buffer.get()];
         buffer.get(tmpName);
         this.name = new String(tmpName);
         this.type = buffer.get();
         this.locked = buffer.get() != 0;
         if (!this.folder) {
            buffer.position(buffer.position() + 5);
         }

      }

      public boolean isFolder() {
         return this.folder;
      }

      public short getID() {
         return this.id;
      }

      public short getParentID() {
         return this.parent_id;
      }

      public String getName() {
         return this.name;
      }

      public byte getType() {
         return this.type;
      }

      public boolean isLocked() {
         return this.locked;
      }

      public String toString() {
         return String.format("ProjectEntry[%s] : Folder[%b], ID[%d], Parent[%d], Type[%d], Locked[%b]", this.name, this.folder, this.id, this.parent_id, this.type, this.locked);
      }
   }
}
